package com.glodon.async.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.glodon.async.service.RemoteService;
import com.glodon.async.service.UserBatchService;
import lombok.Data;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.*;

/**
 * 最终实现方案
 * @Author: lilin
 * @Date: 2022/8/13
 */
@Service("userBatchService")
public class UserBatchServiceImpl implements UserBatchService {

    @Autowired
    private RemoteService remoteService;

    // 阻塞队列   安全/性能考虑
    LinkedBlockingQueue<QueryRequest> queue = new LinkedBlockingQueue<>();

    @Override
    public JSONObject getUserInfoBatch(String userId) throws Exception {
        // 生成唯一标识
        String serialNo = UUID.randomUUID().toString();

        CompletableFuture<JSONObject> future = new CompletableFuture<>();

        // 组装参数
        QueryRequest request = new QueryRequest();
        request.setSerialNo(serialNo);
        request.setUserId(userId);
        request.setStartTime(System.currentTimeMillis());
        request.setCompletableFuture(future);
        // 将请求放入队列中
        queue.add(request);
        // 等待响应结果
        return future.get();
    }

    @PostConstruct
    @Async
    public void bussines(){
        // 创建定时线程池，初始化100毫秒后执行，每次间隔10毫秒
        ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                if (queue.size() == 0){
                    return;
                }

                int size = queue.size();
                System.out.println(DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "批量处理的数据量：" + size);

                // 标记：有哪些请求进行了批量查询，目的：为了和结果对应，响应到对应的客户端
                List<QueryRequest> requests = new ArrayList<>(size);
                // 封装批量请求的参数
                List<Map<String, Object>> params = new ArrayList<>(size);

                for (int i = 0; i < size; i++) {
                    QueryRequest poll = queue.poll();

                    Map<String, Object> param = new HashMap<>();
                    param.put("userId", poll.getUserId());
                    param.put("serialNo", poll.getSerialNo());
                    param.put("startTime", poll.getStartTime());
                    params.add(param);

                    requests.add(poll);
                }

                // 批量返回结果
                List<JSONObject> resultList = remoteService.getUserNameBath(params);

                // 因为执行N此请求，就要有N此返回，所以按照请求的list来循环
                for (QueryRequest request : requests) {
                    String serialNo = request.getSerialNo();
                    for (JSONObject jsonObject : resultList) {
                        String resSerialNo = jsonObject.getString("serialNo");
                        if (serialNo.equals(resSerialNo)){
                            // 对应completable.get()获取返回值
                            jsonObject.put("resultTime", System.currentTimeMillis() - request.getStartTime());
                            System.out.println("请求时间：" + DateFormatUtils.format(new Date(request.getStartTime()), "yyyy-MM-dd HH:mm:ss") + "请求ID：" + request.getUserId() + "  响应结果：" + jsonObject.toJSONString());
                            request.getCompletableFuture().complete(jsonObject);
                            break;
                        }
                    }
                }
            }
        }, 100L, 10, TimeUnit.MILLISECONDS);
    }

}

@Data
class QueryRequest{
    private String userId;
    private String serialNo;
    private Long startTime;
    private CompletableFuture<JSONObject> completableFuture;
}
